﻿using Com.Lancetinc.Evs.Data;
using Com.Lancetinc.Evs.Data.Domain;
using Com.Lancetinc.Evs.Helpers;
using System;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using NLog;

namespace Com.Lancetinc.Evs.Services;

public class ExperBackupService
{
    // 24f3bff3b3961b4f54ee5f146b09420c
    private static string BackupPwd = Md5Utils.Encrypt("levs_db_20230407");

    private static readonly ILogger Logger = LogManager.GetCurrentClassLogger();

    private const string _expersJsonFileName = "expers.json";

    public Task<bool> ExportAsync(string zipFilePath, Exper[] expers, int dbVersion, IProgress<float> progress, CancellationToken ct)
    {
        return Task.Factory.StartNew(() => Export(zipFilePath, expers, dbVersion, progress, ct), ct);
    }

    /// <summary>
    /// 导出数据库
    /// </summary>
    /// <param name="zipFilePath">导出到这个文件</param>
    /// <param name="expers">实验数据</param>
    /// <param name="dbVersion">数据库版本</param>
    /// <param name="progress">进度</param>
    /// <param name="ct"></param>
    public bool Export(string zipFilePath, Exper[] expers, int dbVersion, IProgress<float> progress, CancellationToken ct)
    {
        if (expers.Length == 0)
            return false;

        var tempDir = TempDirHelper.GetTempDirectory();
        try
        {
            var expFile = Path.Combine(tempDir, _expersJsonFileName);
            var expInfo = new ExperBackupInfo
            {
                Expers = expers,
                Version = dbVersion,
                BackupTime = DateTime.Now,
                AppVersion = AppConsts.InnerAppVersion
            };
            var jsonStr = JsonUtil.Stringify(expInfo);
            File.WriteAllText(expFile, jsonStr, Encoding.UTF8);
            if (ct.IsCancellationRequested)
                return false;

            int totalFiles = expers.Length;
            int finishCount = 0;
            float weight = 0.3F;
            var historyRecordDir = Path.Combine(tempDir, ExperManager.HistoryRecordDir);
            float p = 0;
            foreach (var exper in expers)
            {
                if (ct.IsCancellationRequested)
                    return false;

                var dataDir = new DirectoryInfo(ExperManager.Default.GetExperDataDir(exper.SeqNo));
                if (!dataDir.Exists)
                    continue;

                var targetDir = Path.Combine(historyRecordDir, dataDir.Name);
                DirUtil.CopyDirectory(dataDir.FullName, targetDir);
                finishCount++;
                p = weight * finishCount / totalFiles;
                progress?.Report(p);
            }

            var tempDi = new DirectoryInfo(tempDir);
            var progress2 = new BackupProgress((p2) =>
            {
                p = weight + (1 - weight) * p2;
                progress?.Report(p);
            });
            try
            {
                CompressHelper.Zip(tempDi, zipFilePath, BackupPwd, progress2, ct);
            }
            catch (Exception e)
            {
                Logger.Error(e);
                if (!ct.IsCancellationRequested)
                    throw; // 压缩时取消可能会抛异常
            }

            if (ct.IsCancellationRequested)
            {
                FileUtil.Delete(zipFilePath);
                return false;
            }

            progress?.Report(1);
        }
        finally
        {
            DirUtil.DeleteDirectory(tempDir);
        }

        return true;
    }

    /// <summary>
    /// 导入数据库
    /// </summary>
    public async Task<bool> ImportAsync(string zipFilePath, StringBuilder sbError)
    {
        var outDir = new DirectoryInfo(TempDirHelper.GetTempDirectory());
        try
        {
            await Task.Factory.StartNew(() => { CompressHelper.UnZip(zipFilePath, outDir, BackupPwd); });
            var jsonFile = Path.Combine(outDir.FullName, _expersJsonFileName);
            var historyRecordDir = Path.Combine(outDir.FullName, ExperManager.HistoryRecordDir);
            if (!File.Exists(jsonFile) || !Directory.Exists(historyRecordDir))
            {
                //无效的数据库文件
                sbError.Append(I18nHelper.Default.GetMessage("HistoryPageUserControl.InvalidDbFile"));
                return false;
            }

            var jsonStr = File.ReadAllText(jsonFile, Encoding.UTF8);
            var bkInfo = JsonUtil.Parse<ExperBackupInfo>(jsonStr);
            var expers = bkInfo.Expers;
            var existsSeqNos = AppRepositories.Exper.CheckExists(expers.Select(x => x.SeqNo).ToArray());
            bool overrideFlag = false;
            if (existsSeqNos.Length > 0)
            {
                var existsCount = existsSeqNos.Length;
                var seqNos = string.Join(",", existsSeqNos.Take(3));
                if (existsSeqNos.Length > 3)
                {
                    seqNos += I18nHelper.Default.GetMessage("HistoryPageUserControl.Etc"); //...等
                }

                var msg = I18nHelper.Default.GetMessageWithArgs("HistoryPageUserControl.ConfirmOverwrite", existsCount,
                    seqNos); //已经存在，是否覆盖？

                var res = await MessageHelper.ShowYesNoCancelAsync(msg);
                if (res == MessageBoxResult.Cancel)
                    return false;
                overrideFlag = res == MessageBoxResult.Yes;
            }

            // 不覆盖
            if (!overrideFlag)
            {
                expers = expers.Where(x => !existsSeqNos.Contains(x.SeqNo)).ToArray();
                if (expers.Length == 0)
                    return false; // 没有需要导入的实验

                existsSeqNos = null;
            }

            return await Task.Factory.StartNew(() =>
            {
                AppRepositories.Exper.BatchImport(expers, existsSeqNos);

                foreach (var exper in expers)
                {
                    try
                    {
                        var dataDir = new DirectoryInfo(ExperManager.Default.GetExperDataDir(exper.SeqNo));
                        if (dataDir.Exists)
                        {
                            dataDir.Delete(true);
                        }

                        Thread.Sleep(500);
                        var sourceDir = Path.Combine(historyRecordDir, dataDir.Name);
                        DirUtil.CopyDirectory(sourceDir, dataDir.FullName, true);
                    }
                    catch (Exception e)
                    {
                        var msg = I18nHelper.Default.GetMessageWithArgs("HistoryPageUserControl.ImportXFailed",
                            exper.SeqNo);
                        sbError.AppendLine(msg + e.Message);
                    }
                }

                return true;
            });
        }
        catch (Exception e)
        {
            Logger.Error(e);
        }
        finally
        {
            DirUtil.DeleteDirectory(outDir.FullName);
        }

        return false;
    }

    public class ExperBackupInfo
    {
        public Exper[] Expers { get; set; }

        /// <summary>
        /// 数据库版本
        /// </summary>
        public int Version { get; set; }

        /// <summary>
        /// 备份时间
        /// </summary>
        public DateTime BackupTime { get; set; }

        /// <summary>
        /// 导出时的程序版本号
        /// </summary>
        public string AppVersion { get; set; }
    }

    public class BackupProgress : IProgress<float>
    {
        public BackupProgress(Action<float> onProgress)
        {
            OnProgress = onProgress;
        }

        public Action<float> OnProgress { get; }

        /// <inheritdoc />
        public void Report(float value)
        {
            OnProgress?.Invoke(value);
        }
    }
}